<script setup>
import { useRoute, useRouter } from 'vue-router'
import { useEventListener } from '@vueuse/core/index'
import { useFileDialog } from '@vueuse/core'
import { ElMessage, ElMessageBox, ElProgress } from 'element-plus'
import { v4 } from 'uuid'
import {
  addFolder,
  addFile,
  deleteFile,
  downloadFile,
  getFileInfo,
  getFileList,
  updateFile,
  uploadFile,
  resourceRestore,
  removeForever,
} from '@/assets/api/document'
import useEventBus from '@/use/use-event-bus'

const props = defineProps({
  projectFolderId: {
    type: String,
    default: '',
  },
})
const emit = defineEmits(['updateFolderId'])
const route = useRoute()
const fileDialog = useFileDialog()
fileDialog.onChange((files) => files?.length && handleUploadFileChange(files))
const breadcrumbList = ref([])
const viewType = ref('icon')
const fileList = ref([])
const filterFileList = computed(() => {
  return fileList.value.filter((i) => i.resourceName.includes(searchWord.value))
})
const contentMenuShow = ref(false)
const contentMenuStyle = ref({
  left: 0,
  top: 0,
})
// 当前文件
const currentFile = ref({})
// 创建文件夹弹窗开关
const createFolderOrFileVisible = ref(false)
const createDialogTitle = ref('')
const createFileExtend = ref('')
const createResourceName = ref('')

const form = ref({
  folderParentId: null,
  resourceId: null,
  resourceName: '',
  type: '',
})
const formRules = reactive({
  resourceName: [{ required: true, message: '文件夹名称必填', trigger: 'blur' }],
})

// 加载
const loading = ref(false)
const uploadProgressVisible = ref(false)
// 搜索关键词
const searchWord = ref('')
// 勾选的文件
const checkedFiles = ref([])
// 上传文件总数量
const uploadFileTotalNumber = ref(0)
// 已上传文件数量
const uploadFinishNumber = ref(0)
const uploadPercentage = computed(() => {
  if (!uploadFileTotalNumber.value) return 0
  return (uploadFinishNumber.value / uploadFileTotalNumber.value) * 100
})
const isFolder = ref(false)
// 当前文件夹id
const folderId = computed(() => {
  return props.projectFolderId ? props.projectFolderId : route.query.id || null
})

watch(
  folderId,
  (v) => {
    if (v) {
      getFileListData()
    }
  },
  { immediate: true }
)

const eventBus = useEventBus()
eventBus.on('fileUploadProgress', updateUploadProgress)

// 切换视图展示的时候，详情重置
watch(viewType, (v) => {
  if (v) {
    currentFile.value = {}
  }
})

function updateUploadProgress(progressData) {
  if (!isFolder.value) {
    uploadFinishNumber.value = progressData.progress
    if (uploadFinishNumber.value === uploadFileTotalNumber.value) {
      handleUploadSuccess()
    }
  }
}

function getFileListData(obj) {
  loading.value = true
  getFileList({
    folderId: folderId.value || null,
    ...obj,
  }).then((res) => {
    if (res.code === 200) {
      const fn2 = (pid) => {
        const self = res.data.filter((i) => i.folderId !== null).find((i) => i.folderId.toString() === pid)
        if (self?.folderParentId) {
          return [...fn2(self.folderParentId.toString()), self]
        }
        return [self]
      }
      if (folderId.value === '1' || folderId.value === '5') {
        fileList.value = res.data.filter((i) => i.folderParentId.toString() !== '0')
        breadcrumbList.value = fn2(folderId.value)
      } else {
        fileList.value = res.data.filter((i) => i.folderParentId.toString() === folderId.value)
        breadcrumbList.value = fn2(folderId.value)
      }
    } else {
      ElMessage.warning(res.msg)
    }
    loading.value = false
  })
}

/**
 *  创建文件弹出模态框函数
 * @param type
 * @param extend
 */
const createFileDialog = (type, extend = null) => {
  if (type === 'folder') {
    createDialogTitle.value = '创建文件夹'
    createResourceName.value = '文件夹名称'
  } else {
    createDialogTitle.value = `创建${type && type.toUpperCase()}文档`
    createResourceName.value = '文档名称'
    createFileExtend.value = extend
    form.value.type = type
  }
  createFolderOrFileVisible.value = true
}

const detailLoading = ref(false)

function handleFileClick(file) {
  detailLoading.value = true
  getFileInfo({ resourceId: file.resourceId, pageNum: 1, pageSize: 10 }).then((res) => {
    if (res.code === 200) {
      res.data.baseInfo.operateRecord = res.data.operateRecord
      res.data.baseInfo.authority = JSON.parse(res.data.folderPermissions || '[]')
      res.data.baseInfo.folderUser = res.data.folderUser
      currentFile.value = res.data.baseInfo
      pageSizeMore.value = 0
    }
    detailLoading.value = false
  })
}

// 可在线查看文件类型
const showImageViewer = ref(false)
const url = ref('')

function closeImgViewer() {
  showImageViewer.value = false
}

const router = useRouter()

function handleFileDblclick(file) {
  // 回收站文件特殊处理
  if (file.folderParentId === 5) {
    return
  }
  if (file.isRename) return
  const { resourceType } = file
  if (resourceType === 'folder') {
    // 根据传参判断是否是在项目中打开
    if (route.params.id === '1') {
      emit('highlightCurrent', file.levelTree.folderId)
    }
    if (props.projectFolderId) {
      emit('updateFolderId', file.folderId)
    } else {
      router.push({
        path: `/chat/fileManagement`,
        query: {
          ...route.query,
          id: file.folderId,
        },
      })
    }
  }
}

/**
 * 重命名完成
 */
function renameFinish(resourceName) {
  updateFile({ ...currentFile.value, resourceName }).then((res) => {
    if (res.code === 200) {
      currentFile.value.isRename = false
      currentFile.value = null
      contentMenuShow.value = false
      getFileListData()
    } else {
      ElMessage.error(res.msg)
    }
  })
}

function onContextmenu(e, file = null) {
  e.preventDefault()
  detailFlag.value = false
  currentFile.value = file
  contentMenuStyle.value = {
    left: e.x + 'px',
    top: e.y + 'px',
  }
  contentMenuShow.value = true
}

/**
 * 重命名
 */
function rename() {
  currentFile.value.isRename = true
}

/**
 * 弹窗关闭
 */
function close() {
  formRef.value.clearValidate()
  createFolderOrFileVisible.value = false
  form.value = {
    prentId: null,
    resourceName: '',
    isRename: false,
    // 以下字段用在文件创建
    folderParentId: null,
    type: null,
  }
}

/**
 * 提交表单
 */
const formRef = ref()

function submit() {
  formRef.value.validate(async (valid) => {
    if (valid) {
      form.value.folderParentId = folderId.value
      if (form.value.type) {
        addFile(form.value).then((res) => {
          if (res.code === 200) {
            ElMessage.success('新建成功')
            getFileListData()
            close()
          } else {
            ElMessage.warning(res.msg)
          }
        })
      } else {
        addFolder(form.value).then((res) => {
          if (res.code === 200) {
            ElMessage.success('新建成功')
            getFileListData()
            close()
          } else {
            ElMessage.warning(res.msg)
          }
        })
      }
    }
  })
}

// 恢复文件
function handleRecover(file) {
  resourceRestore(file.resourceId).then((res) => {
    if (res.code === 200) {
      ElMessage.success('恢复成功')
      getFileListData()
    }
  })
}

// 彻底删除
function handleThoroughDelete(file) {
  ElMessageBox.confirm(`确认彻底删除${file.resourceName}么?`, '删除确认', {
    cancelButtonText: '取消',
    confirmButtonText: '确认',
    type: 'warning',
  })
    .then(() => {
      removeForever(file.resourceId).then((res) => {
        if (res.code === 200) {
          ElMessage.success('彻底删除成功')
          getFileListData()
        }
      })
    })
    .catch(() => {})
}

/**
 * 删除
 */
function handleDeleteFile() {
  const delSingle = checkedFiles.value.length <= 1
  const content = delSingle
    ? `${currentFile.value.resourceType === 'folder' ? '文件夹' : '文件'}"${currentFile.value.resourceName}"`
    : '这些文件'
  ElMessageBox.confirm(`确认删除${content}么?`, '删除确认', {
    cancelButtonText: '取消',
    confirmButtonText: '确认',
    type: 'warning',
  })
    .then(() => {
      const ids = delSingle ? [currentFile.value.resourceId] : checkedFiles.value.map((i) => i.resourceId)
      deleteFile({ ids }).then((res) => {
        if (res.code === 200) {
          ElMessage.success('删除成功')
          checkedFiles.value = []
          getFileListData()
        }
      })
    })
    .catch(() => {})
}

/**
 * 上传文件
 */
function handleUploadFileChange(files) {
  files = Array.from(files)
  isFolder.value = files[0].webkitRelativePath !== ''
  if (isFolder.value) {
    handleUploadFolder(files)
    uploadFileTotalNumber.value = files.length
    uploadProgressVisible.value = true
  } else {
    handleUploadFile(folderId.value, files)
    uploadFileTotalNumber.value = 100
  }
}

function handleUploadFolder(files) {
  files = files.filter((i) => !/^~\$.*\.(xlsx|xls|doc|docx)$/.test(i.name))
  const fileTree = []
  const buildTree = (paths, file, arr) => {
    const resourceName = paths.shift()
    let obj = arr.find((i) => i.resourceName === resourceName)
    if (!obj) {
      obj = {
        resourceName,
        files: [],
        children: [],
      }
      arr.push(obj)
    }
    if (paths.length) {
      buildTree(paths, file, obj.children)
    } else {
      obj.files.push(file)
    }
  }
  const uploadFileTree = async (arr, folderParentId) => {
    for (let i = 0; i < arr.length; i++) {
      const res = await addFolder({ folderParentId, resourceName: arr[i].resourceName })
      if (res.code === 200) {
        if (arr[i].files.length) {
          handleUploadFile(res.data.folderId, arr[i].files)
            .then(() => {
              uploadFinishNumber.value += arr[i].files.length
              if (uploadFinishNumber.value === uploadFileTotalNumber.value) {
                ElMessage.success('上传成功')
                setTimeout(() => {
                  handleUploadSuccess()
                }, 1000)
              } else {
                uploadFileTree(arr[i].children, res.data.folderId)
              }
            })
            .catch((err) => {
              ElMessage.warning(err.msg)
            })
        } else {
          uploadFileTree(arr[i].children, res.data.folderId)
        }
      }
    }
  }
  files.forEach((file) => {
    const paths = file.webkitRelativePath.split('/')
    paths.pop()
    buildTree(paths, file, fileTree)
  })
  uploadFileTree(fileTree, folderId.value)
}

function handleUploadFile(folderParentId, files) {
  return new Promise((resolve, reject) => {
    const formData = new FormData()
    formData.append('fileUploadKey', v4())
    formData.append('folderParentId', folderParentId)
    files.forEach((file) => {
      formData.append('files', file)
    })
    uploadProgressVisible.value = true
    uploadFile(formData).then((res) => {
      if (res.code === 200) {
        resolve()
      } else {
        reject(res)
      }
    })
  })
}

function handleUploadSuccess() {
  ElMessage.success('上传成功')
  uploadProgressVisible.value = false
  uploadFileTotalNumber.value = 0
  uploadFinishNumber.value = 0
  fileDialog.reset()
  getFileListData()
}

const detailFlag = ref(false)

function openDetail() {
  detailFlag.value = !detailFlag.value
}

watch(detailFlag, (val) => {
  document.getElementsByClassName('file-list')[0].style.width = val ? '82%' : '100%'
  document.getElementsByClassName('file-detail-info')[0].style.width = val ? '300px' : '0'
  document.getElementsByClassName('file-detail-info')[0].style.transform = val ? 'translateX(0)' : 'translateX(310px)'
})

/**
 * 下载文件
 */
function downloadFiles() {
  downloadFile(currentFile.value.resourceId).then((res) => {
    let mimeType = currentFile.value.mimeType
    let type = mimeType ? mimeType : 'application/zip'
    let blob = new Blob([res], { type: type })
    let url = window.URL.createObjectURL(blob)
    const link = document.createElement('a')
    link.href = url
    link.download = `${currentFile.value.resourceName}`
    link.click()
    URL.revokeObjectURL(url)
  })
}

/*
加载
*/
const pageSizeMore = ref(0)

onMounted(() => {
  useEventListener('click', () => {
    contentMenuShow.value = false
  })
})
</script>

<template>
  <div class="file-list">
    <div v-loading="loading" class="file-list-content">
      <FileListHead
        v-model:search-word="searchWord"
        :breadcrumb-list="
          props.projectFolderId ? breadcrumbList.filter((item) => item.folderParentId !== 0) : breadcrumbList
        "
        :file-list="filterFileList"
        :routerFlag="props.projectFolderId"
        :view-type="viewType"
        @openDetail="openDetail"
        @search="getFileListData"
        @updateFolderId="(id) => emit('updateFolderId', id)"
        @viewTypeChange="(v) => (viewType = v)"></FileListHead>
      <FileListBody
        v-model:checked-files="checkedFiles"
        :file="currentFile"
        :file-list="filterFileList"
        :view-type="viewType"
        @bodyContextmenu="onContextmenu"
        @fileClick="handleFileClick"
        @fileContextmenu="onContextmenu"
        @fileDblclick="handleFileDblclick"
        @fileMoreClick="onContextmenu"
        @renameFinish="renameFinish"></FileListBody>
      <ul
        v-if="contentMenuShow && folderId !== '5'"
        :style="[contentMenuStyle, !currentFile && folderId === '1' ? 'display:none' : '']"
        class="file-contextmenu">
        <template v-if="currentFile || checkedFiles.length">
          <li @click="handleFileDblclick(currentFile)">打开</li>
          <li @click="downloadFiles">下载</li>
          <!-- <li>收藏</li> -->
          <el-divider></el-divider>
        </template>
        <template v-if="folderId !== '1' || !currentFile">
          <li @click="createFileDialog('folder')">
            <SvgIcon name="new-folder" />
            新建文件夹
          </li>
          <li @click="fileDialog.open({ multiple: true })">
            <SvgIcon name="upload-file" />
            上传文件
          </li>
          <li @click="fileDialog.open({ directory: true })">
            <SvgIcon name="upload-folder" />
            上传文件夹
          </li>
          <li class="split-line" @click="createFileDialog('drawio', 'drawio')">
            <SvgIcon name="workflow" />
            流程图
          </li>
          <li @click="createFileDialog('mind', 'mind')">
            <SvgIcon name="mind" />
            思维导图
          </li>
          <li class="split-line" @click="createFileDialog('word', 'docx')">
            <SvgIcon name="word" />
            Word文档
          </li>
          <li @click="createFileDialog('excel', 'xlsx')">
            <SvgIcon name="excel" />
            Excel文档
          </li>
          <li @click="createFileDialog('ppt', 'pptx')">
            <SvgIcon name="pptx" />
            PPT演示文稿
          </li>
        </template>
        <template v-if="currentFile || checkedFiles.length">
          <li v-if="currentFile" @click="rename">重命名</li>
          <el-divider></el-divider>
          <li style="color: var(--elp-color-error)" @click="handleDeleteFile">删除</li>
        </template>
      </ul>
      <ul v-else-if="contentMenuShow && currentFile" :style="contentMenuStyle" class="file-contextmenu">
        <li @click="handleRecover(currentFile)">恢复</li>
        <li style="color: var(--elp-color-error)" @click="handleThoroughDelete(currentFile)">彻底删除</li>
      </ul>
      <TaskChatDialog v-model="createFolderOrFileVisible" :title="createDialogTitle" width="400px">
        <el-form ref="formRef" :model="form" :rules="formRules">
          <el-form-item :label="createResourceName" prop="resourceName">
            <el-input v-model="form.resourceName" :placeholder="createResourceName" maxlength="50" show-word-limit>
              <template v-if="form.type" #append>.{{ createFileExtend }}</template>
            </el-input>
          </el-form-item>
        </el-form>
        <template #footer>
          <el-button @click="close">取消</el-button>
          <el-button type="primary" @click="submit">确定</el-button>
        </template>
      </TaskChatDialog>
      <!--上传进度弹窗-->
      <Teleport to="body">
        <div v-if="uploadProgressVisible" class="upload-progress">
          <div class="prompt">上传中, 请勿关闭浏览器或切换菜单</div>
          <el-progress :percentage="uploadPercentage" :stroke-width="12" striped striped-flow>
            <span>{{ uploadFinishNumber }} / {{ uploadFileTotalNumber }}</span>
          </el-progress>
        </div>
      </Teleport>
    </div>
    <!--文件详情-->
    <div v-loading="detailLoading" class="file-detail-info">
      <FileDetail :file="currentFile" @close="detailFlag = false"></FileDetail>
    </div>
    <!-- 图片查看器 -->
    <el-image-viewer v-if="showImageViewer" :url-list="[url]" @close="closeImgViewer" />
  </div>
</template>

<style lang="scss" scoped>
.file-list {
  position: relative;
  flex: 1;
  height: 100%;
  display: flex;
  justify-content: space-between;

  .file-detail-info {
    background-color: var(--elp-bg-color);
    box-shadow: var(--elp-box-shadow);
    transform: translateX(310px);
    width: 0;
    transition: all 0.3s;
    border-radius: 0 8px 8px 0;
  }

  .file-list-content {
    position: relative;
    padding: 18px 32px;
    height: 100%;
    @include use-flex(normal, normal, column);
    width: 100%;
    transition: all 0.3s;

    .file-contextmenu {
      position: fixed;
      width: 200px;
      padding: 10px;
      margin: 0;
      background-color: var(--elp-bg-color);
      box-shadow: var(--elp-box-shadow);
      list-style: none;
      user-select: none;
      border-radius: 5px;
      z-index: 3;

      .elp-divider {
        margin: 2px 0;
      }

      li {
        @include use-flex(center);
        cursor: pointer;
        padding: 8px;
        border-radius: 5px;

        :deep(.svg-icon) {
          margin-right: 10px;
        }

        &:hover {
          background-color: var(--elp-color-info-light-9);
        }

        svg {
          width: 22px !important;
          height: 22px !important;
        }
      }

      .split-line {
        border-top: 1px solid #ccc;
        border-top-right-radius: 0;
        border-top-left-radius: 0;

        &:hover {
          border-top: 1px solid #ccc;
          border-top-right-radius: 5px;
          border-top-left-radius: 5px;
        }
      }
    }
  }
}
</style>
<style lang="scss">
.upload-progress {
  position: absolute;
  padding: 20px;
  left: 50%;
  bottom: 50%;
  width: 400px;
  translate: -50% -50%;
  background-color: var(--elp-bg-color);
  border-radius: 5px;
  box-shadow: var(--elp-box-shadow);

  .prompt {
    margin-bottom: 5px;
  }
}
</style>
